#include <string>
#include <array>
#include <iostream>
#include <iomanip>
#include <system_error>

#include <unistd.h>
#include <sys/wait.h>

class Pipe
{
  public:
    Pipe()
    {
        if (::pipe(handles_.data()) < 0)
        {
            throw std::system_error(errno, std::system_category(), "pipe()");
        }
    }
    ~Pipe()
    {
        ::close(handles_.at(0));
        ::close(handles_.at(1));
    }

    std::string readFromPipe()
    {
        std::array<char, 256> buf;
        size_t bytes = ::read(handles_.at(0), buf.data(), buf.size());
        if (bytes > 0)
        {
            return {buf.data(), bytes > buf.size() ? buf.size() : bytes};
        }
        return {};
    }

    int writeToPipe(const std::string& msg)
    {
        int ret = ::write(handles_.at(1), msg.data(), msg.size());
        if (ret < 0)
        {
            throw std::system_error(errno, std::system_category(), "write()");
        }
        return ret;
    }

    void redirect()
    {
        // Duplicate FD to STDOUT, closing STDOUT and making it open on the same
        // FD.
        ::dup2(handles_.at(1), STDOUT_FILENO);
        ::close(handles_.at(0));
        ::close(handles_.at(1));
    }

  private:
    std::array<int, 2> handles_;
};

using namespace std;
int main(int argc, char** argv)
{
    Pipe p;
    if (::fork() == 0)
    {
        // child redirects stdout to pipe
        p.redirect();
        ::execlp("ls", "ls", nullptr);
    }
    else
    {
        // parent waits until child finish
        ::wait(nullptr);
        cout << "child execlp gets: \n" << quoted(p.readFromPipe()) << endl;
    }
    return 0;
}